home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 23 / AACD 23.iso / AACD / Online / opennap / server_login.c < prev    next >
C/C++ Source or Header  |  2001-06-08  |  13KB  |  489 lines

  1. /* Copyright (C) 2000-1 drscholl@users.sourceforge.net
  2.    This is free software distributed under the terms of the
  3.    GNU Public License.
  4.  
  5.    $Id: server_login.c,v 1.57 2001/02/15 08:39:45 drscholl Exp $ */
  6.  
  7. #include <fcntl.h>
  8. #include <string.h>
  9. #include <errno.h>
  10. #include <stdlib.h>
  11. #include <limits.h>
  12. #include <time.h>
  13. #include "opennap.h"
  14. #include "debug.h"
  15. #include "md5.h"
  16.  
  17. /* process a request to establish a peer server connection */
  18. /* <name> <nonce> <compression> */
  19. HANDLER (server_login)
  20. {
  21.     char   *fields[3];
  22.     char    hash[33];
  23.     unsigned int ip;
  24.     struct md5_ctx md;
  25.     int     compress;
  26.     server_auth_t *auth;
  27.  
  28.     (void) tag;
  29.     (void) len;
  30.     ASSERT (validate_connection (con));
  31.     if (con->class != CLASS_UNKNOWN)
  32.     {
  33.     send_cmd (con, MSG_SERVER_ERROR, "reregistration is not supported");
  34.     destroy_connection (con);
  35.     return;
  36.     }
  37.  
  38.     if (split_line (fields, sizeof (fields) / sizeof (char *), pkt) != 3)
  39.     {
  40.     log ("server_login: wrong number of fields");
  41.     send_cmd (con, MSG_SERVER_ERROR, "link failed: invalid parameters");
  42.     destroy_connection (con);
  43.     return;
  44.     }
  45.  
  46.     log ("server_login: request from %s (%s)", fields[0], con->host);
  47.  
  48.     /* check to see if this server is already linked */
  49.     if (is_linked (fields[0]))
  50.     {
  51.     log ("server_login: %s is already linked", fields[0]);
  52.     notify_mods (SERVERLOG_MODE,
  53.              "Server %s link failed: already linked", fields[0]);
  54.     send_cmd (con, MSG_SERVER_ERROR, "link failed: already linked");
  55.     destroy_connection (con);
  56.     return;
  57.     }
  58.  
  59.     auth = find_server_auth (fields[0]);
  60.     if (!auth)
  61.     {
  62.     /* no permission to link */
  63.     log ("server_login: %s is not in servers file", fields[0]);
  64.     notify_mods (SERVERLOG_MODE,
  65.              "Server %s link failed: not in servers file", fields[0]);
  66.     send_cmd (con, MSG_SERVER_ERROR, "link failed: not in servers file");
  67.     destroy_connection (con);
  68.     return;
  69.     }
  70.  
  71.     /* if an alias for this server is given, don't let it link unless its
  72.      * reporting its name as the alias instead of the real name
  73.      */
  74.     if (auth->alias && strcasecmp (auth->alias, fields[0]))
  75.     {
  76.     /* warn the local mods+ */
  77.     notify_mods (SERVERLOG_MODE,
  78.              "Server %s link failed: must use alias", auth->alias);
  79.     /* notify the peer server why we refused to link */
  80.     send_cmd (con, MSG_SERVER_ERROR,
  81.           "link failed: you must set your server_name to %s",
  82.           auth->alias);
  83.     destroy_connection (con);
  84.     return;
  85.     }
  86.  
  87.     /* make sure this connection is coming from where they say they are */
  88.     /* TODO: make this nonblocking for the rest of the server */
  89.     ip = lookup_ip (auth->name);
  90.  
  91.     /* con->ip is little-endian, so we need to convert it */
  92.     if (ip != BSWAP32 (con->ip))
  93.     {
  94.     char    tmp[sizeof ("xxx.xxx.xxx.xxx")];
  95.  
  96.     /* inet_ntoa() uses a static buffer, so we need to copy the first
  97.      * call so it doesn't get clobbered
  98.      */
  99.     strfcpy (tmp, my_ntoa (BSWAP32 (con->ip)), sizeof (tmp));
  100.     log ("server_login: %s(%s) does not match %s(%s)",
  101.          con->host, tmp, fields[0], my_ntoa (ip));
  102.     send_cmd (con, MSG_SERVER_ERROR,
  103.           "link failed: IP address does not match %s", fields[0]);
  104.     notify_mods (SERVERLOG_MODE, "Server %s link failed: %s != %s",
  105.              fields[0], fields[0], my_ntoa (BSWAP32 (con->ip)));
  106.     destroy_connection (con);
  107.     return;
  108.     }
  109.  
  110.     /* if the peer server connected to us we will just have their ip address
  111.      * as the host, clear that and use the nickname or real dns name as
  112.      * defined by the servers file.
  113.      */
  114.     FREE (con->host);
  115.     con->host = STRDUP (auth->alias ? auth->alias : auth->name);
  116.  
  117.     compress = atoi (fields[2]);
  118.     if (compress < 0 || compress > 9)
  119.     {
  120.     log ("server_login: invalid compression level %s", fields[2]);
  121.     notify_mods (SERVERLOG_MODE,
  122.              "Server %s link failed: invalid compression level %s",
  123.              con->host, fields[2]);
  124.     send_cmd (con, MSG_SERVER_ERROR, "invalid compression level %d",
  125.           compress);
  126.     destroy_connection (con);
  127.     return;
  128.     }
  129.     con->compress =
  130.     (compress < Compression_Level) ? compress : Compression_Level;
  131.  
  132.     /* notify local admins of the connection request */
  133.     notify_mods (SERVERLOG_MODE, "Server %s requested link", con->host);
  134.  
  135.     /* if this is a new request, set up the authentication info now */
  136.     if (!con->server_login)
  137.     {
  138.     con->server_login = 1;
  139.     if ((con->opt.auth = CALLOC (1, sizeof (AUTH))) == 0)
  140.     {
  141.         OUTOFMEMORY ("server_login");
  142.         destroy_connection (con);
  143.         return;
  144.     }
  145.  
  146.     if ((con->opt.auth->nonce = generate_nonce ()) == NULL)
  147.     {
  148.         log ("server_login: failed to generate nonce");
  149.         send_cmd (con, MSG_SERVER_ERROR, "unable to generate nonce");
  150.         destroy_connection (con);
  151.         return;
  152.     }
  153.  
  154.     /* respond with our own login request */
  155.     send_cmd (con, MSG_SERVER_LOGIN, "%s %s %d", Server_Name,
  156.           con->opt.auth->nonce, con->compress);
  157.     }
  158.  
  159.     con->opt.auth->sendernonce = STRDUP (fields[1]);
  160.     if (!con->opt.auth->sendernonce)
  161.     {
  162.     OUTOFMEMORY ("server_login");
  163.     destroy_connection (con);
  164.     return;
  165.     }
  166.  
  167.     /* send our challenge response */
  168.     /* hash the peers nonce, our nonce and then our password */
  169.     md5_init_ctx (&md);
  170.     md5_process_bytes (con->opt.auth->sendernonce,
  171.                strlen (con->opt.auth->sendernonce), &md);
  172.     md5_process_bytes (con->opt.auth->nonce, strlen (con->opt.auth->nonce),
  173.                &md);
  174.     md5_process_bytes (auth->my_pass, strlen (auth->my_pass), &md);
  175.     md5_finish_ctx (&md, hash);
  176.     expand_hex (hash, 16);
  177.     hash[32] = 0;
  178.  
  179.     /* send the response */
  180.     send_cmd (con, MSG_SERVER_LOGIN_ACK, hash);
  181.  
  182.     log ("server_login: ACK for %s sent", con->host);
  183. }
  184.  
  185. HANDLER (server_login_ack)
  186. {
  187.     struct md5_ctx md5;
  188.     char    hash[33];
  189.     LIST   *list;
  190.     server_auth_t *auth;
  191.  
  192.     (void) tag;
  193.     (void) len;
  194.     ASSERT (validate_connection (con));
  195.  
  196.     if (con->class != CLASS_UNKNOWN)
  197.     {
  198.     send_cmd (con, MSG_SERVER_NOSUCH, "reregistration is not supported");
  199.     return;
  200.     }
  201.  
  202.     if (!con->server_login)
  203.     {
  204.     send_cmd (con, MSG_SERVER_ERROR, "You must login first");
  205.     destroy_connection (con);
  206.     return;
  207.     }
  208.  
  209.     /* look up the entry in our peer servers database */
  210.     auth = find_server_auth (con->host);
  211.     /* this shouldn't happen, but lets be on the safe side */
  212.     if (!auth)
  213.     {
  214.     send_cmd (con, MSG_SERVER_ERROR,
  215.           "link failed: you are not authorized");
  216.     destroy_connection (con);
  217.     return;
  218.     }
  219.  
  220.     /* check the peers challenge response */
  221.     md5_init_ctx (&md5);
  222.     md5_process_bytes (con->opt.auth->nonce, strlen (con->opt.auth->nonce),
  223.                &md5);
  224.     md5_process_bytes (con->opt.auth->sendernonce,
  225.                strlen (con->opt.auth->sendernonce), &md5);
  226.     /* password for them */
  227.     md5_process_bytes (auth->their_pass, strlen (auth->their_pass), &md5);
  228.     md5_finish_ctx (&md5, hash);
  229.     expand_hex (hash, 16);
  230.     hash[32] = 0;
  231.  
  232.     if (strcmp (hash, pkt) != 0)
  233.     {
  234.     log ("server_login(): invalid password for %s", con->host);
  235.     notify_mods (SERVERLOG_MODE,
  236.              "Failed server login from %s: invalid password",
  237.              con->host);
  238.     send_cmd (con, MSG_SERVER_ERROR, "link failed: bad password");
  239.     destroy_connection (con);
  240.     return;
  241.     }
  242.  
  243.     /* done with authentication, free resources */
  244.     FREE (con->opt.auth->nonce);
  245.     FREE (con->opt.auth->sendernonce);
  246.     FREE (con->opt.auth);
  247.     con->server_login = 0;
  248.  
  249.     /* set the recv/send buffer length to 16k for server links */
  250.     set_tcp_buffer_len (con->fd, 16384);
  251.  
  252.     /* put this connection in the shortcut list to the server conections */
  253.     list = CALLOC (1, sizeof (LIST));
  254.     if (!list)
  255.     {
  256.     OUTOFMEMORY ("server_login_ack");
  257.     destroy_connection (con);
  258.     return;
  259.     }
  260.  
  261.     list->data = con;
  262.     Servers = list_push (Servers, list);
  263.  
  264.     con->class = CLASS_SERVER;
  265.     con->opt.server = CALLOC (1, sizeof (SERVER));
  266.     /* set up the compression handlers for this connection */
  267.     init_compress (con, con->compress);
  268.  
  269.     log ("server_login_ack(): server %s has joined", con->host);
  270.  
  271.     notify_mods (SERVERLOG_MODE, "Server %s has joined", con->host);
  272.  
  273.     /* notify peer servers this server has joined the cluster */
  274.     pass_message_args (con, MSG_SERVER_LINK_INFO, "%s %hu %s %hu 2",
  275.                Server_Name, get_local_port (con->fd), con->host,
  276.                con->port);
  277.  
  278.     /* synchronize our state with this server */
  279.     synch_server (con);
  280. }
  281.  
  282. /* 10019 <server> <port> <peer> <peerport> <hops>
  283.  * process remote server join message
  284.  */
  285. HANDLER (link_info)
  286. {
  287.     int     ac, port;
  288.     char   *av[5];
  289.     LIST   *list;
  290.     LINK   *slink;
  291.  
  292.     ASSERT (validate_connection (con));
  293.     CHECK_SERVER_CLASS ("link_info");
  294.     (void) len;
  295.     ac = split_line (av, FIELDS (av), pkt);
  296.     if (ac != 5)
  297.     {
  298.     log ("link_info: wrong number of parameters");
  299.     print_args (ac, av);
  300.     return;
  301.     }
  302.  
  303.     /* check the existing server link list to make sure this info looks ok.
  304.      * the peer should not be listed as a peer to any other server.
  305.      */
  306.     for (list = Servers; list; list = list->next)
  307.     {
  308.     CONNECTION *p = list->data;
  309.  
  310.     if (!strcasecmp (p->host, av[2]))
  311.     {
  312.         log ("link_info: %s is already linked locally", av[2]);
  313.         return;
  314.     }
  315.     }
  316.  
  317.     /* check remote links */
  318.     for (list = Server_Links; list; list = list->next)
  319.     {
  320.     slink = list->data;
  321.     if (!strcasecmp (slink->peer, av[2]))
  322.     {
  323.         log ("link_info: %s is already listed as a peer to %s",
  324.          av[2], slink->server);
  325.         return;
  326.     }
  327.     }
  328.  
  329.     slink = CALLOC (1, sizeof (LINK));
  330.     if (slink)
  331.     {
  332.     slink->server = STRDUP (av[0]);
  333.     slink->peer = STRDUP (av[2]);
  334.     }
  335.     if (!slink || !slink->server || !slink->peer)
  336.     {
  337.     OUTOFMEMORY ("link_info");
  338.     goto error;
  339.     }
  340.     port = atoi (av[1]);
  341.     if (port < 0 || port > 65535)
  342.     {
  343.     log ("link_info: invalid port %d", port);
  344.     port = 0;
  345.     }
  346.     slink->port = port;
  347.     port = atoi (av[3]);
  348.     if (port < 0 || port > 65535)
  349.     {
  350.     log ("link_info: invalid port %d", port);
  351.     port = 0;
  352.     }
  353.     slink->peerport = port;
  354.     slink->hops = atoi (av[4]);
  355.     if (slink->hops < 2)
  356.     {
  357.     log ("link_info: invalid hop count %d", slink->hops);
  358.     slink->hops = 2;    /* at least */
  359.     }
  360.     log ("link_info: %s:%d (%d hops away) via %s:%d",
  361.      slink->peer, slink->peerport, slink->hops,
  362.      slink->server, slink->port);
  363.     list = MALLOC (sizeof (LIST));
  364.     if (!list)
  365.     {
  366.     OUTOFMEMORY ("link_info");
  367.     goto error;
  368.     }
  369.     list->data = slink;
  370.     Server_Links = list_push (Server_Links, list);
  371.     pass_message_args (con, tag, "%s %d %s %d %d", slink->server, slink->port,
  372.                slink->peer, slink->peerport, slink->hops + 1);
  373.     notify_mods (SERVERLOG_MODE, "Server %s has joined", slink->peer);
  374.     return;
  375.   error:
  376.     if (slink)
  377.     {
  378.     if (slink->server)
  379.         FREE (slink->server);
  380.     if (slink->peer)
  381.         FREE (slink->peer);
  382.     FREE (slink);
  383.     }
  384. }
  385.  
  386. /* recursively mark entries to reap */
  387. static void
  388. mark_links (const char *host)
  389. {
  390.     LIST   *list = Server_Links;
  391.     LINK   *link;
  392.  
  393.     ASSERT (host != 0);
  394.     for (; list; list = list->next)
  395.     {
  396.     link = list->data;
  397.     ASSERT (link != 0);
  398.     if (link->port != (unsigned short) -1 &&
  399.         link->peerport != (unsigned short) -1)
  400.     {
  401.         if (!strcasecmp (host, link->server))
  402.         {
  403.         link->port = -1;
  404.         link->peerport = -1;
  405.         /* mark servers connected to this peer */
  406.         mark_links (link->peer);
  407.         }
  408.         else if (!strcasecmp (host, link->peer))
  409.         {
  410.         link->port = -1;
  411.         link->peerport = -1;
  412.         }
  413.     }
  414.     }
  415. }
  416.  
  417. /* reap all server link info behind the server named by `host' */
  418. void
  419. remove_links (const char *host)
  420. {
  421.     LIST  **list, *tmpList;
  422.     LINK   *link;
  423.  
  424.     mark_links (host);
  425.     list = &Server_Links;
  426.     while (*list)
  427.     {
  428.     link = (*list)->data;
  429.     if (link->port == (unsigned short) -1 &&
  430.         link->peerport == (unsigned short) -1)
  431.     {
  432.         tmpList = *list;
  433.         *list = (*list)->next;
  434.         log ("remove_links: removing link %s -> %s",
  435.          link->server, link->peer);
  436.         FREE (tmpList);
  437.         FREE (link->server);
  438.         FREE (link->peer);
  439.         FREE (link);
  440.         continue;
  441.     }
  442.     list = &(*list)->next;
  443.     }
  444. }
  445.  
  446. /* :<server> <time>
  447.  * check the time on the remote server to make sure our clocks are not
  448.  * too skewed for proper link
  449.  */
  450. HANDLER (time_check)
  451. {
  452.     char   *utc;
  453.     int     delta;
  454.  
  455.     (void) tag;
  456.     (void) len;
  457.     CHECK_SERVER_CLASS ("time_check");
  458.     next_arg (&pkt);
  459.     utc = next_arg (&pkt);
  460.     /* refresh our time just in case it took awhile to get here */
  461.     delta = time (&global.current_time) - atoi (utc);
  462.     if (delta < 0)
  463.     delta *= -1;        /* make positive */
  464.     if (Max_Time_Delta > 0)
  465.     {
  466.     if (delta > Max_Time_Delta)
  467.     {
  468.         notify_mods (SERVERLOG_MODE,
  469.              "Server %s clock skewed by %d seconds, link failed.",
  470.              con->host, delta);
  471.         send_cmd (con, MSG_SERVER_ERROR, "Clock skewed by %d seconds",
  472.               delta);
  473.         destroy_connection (con);
  474.         return;
  475.     }
  476.     }
  477.     if (Warn_Time_Delta > 0)
  478.     {
  479.     if (delta > Warn_Time_Delta)
  480.     {
  481.         notify_mods (SERVERLOG_MODE,
  482.              "Server %s clock skewed by %d seconds", con->host,
  483.              delta);
  484.         send_cmd (con, MSG_SERVER_ERROR, "Clock skewed by %d seconds",
  485.               delta);
  486.     }
  487.     }
  488. }
  489.